function compose(middleware) {
  return function (context, next) {
    // last called middleware #
    let index = -1
    return dispatch(0)
    
    function dispatch(i) {
      if (i <= index) return Promise.reject(new Error('next() called multiple times'))
      index = i
      let fn = middleware[i]
      if (i === middleware.length) fn = next
      if (!fn) return Promise.resolve()
      try {
        return Promise.resolve(fn(context, function next() {
          return context.status !== 302 && dispatch(i + 1)
        }))
      } catch (err) {
        return Promise.reject(err)
      }
    }
  }
}

module.exports = class {
  constructor() {
    this.middlewareList = []
  }
  
  add(middleware) {
    if (Array.isArray(middleware)) {
      this.middlewareList = [...this.middlewareList, ...middleware];
    } else {
      this.middlewareList.push(middleware);
    }
    return this;
  }
  
  async go(ctx) {
    let runMiddlewareList = [...this.middlewareList];
    try {
      let fun = compose(runMiddlewareList);
      console.log('go', ctx.status, typeof fun);
      if (ctx.status !== 302) {
        await fun(ctx, null);
      }
    } catch (e) {
      console.log('link error:', e);
    }
  }
}